/**
 * @author Dylan Jones, Ryan Hammonds
 */
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.awt.datatransfer.*;
import java.awt.Toolkit;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;
import org.apache.commons.codec.binary.Hex;


@SuppressWarnings("serial")
public class GUI extends JFrame {
	RainbowTable table;
	JTextField searchForHash;
	JTextField textToHash;
	JTextField hashToCrack;
	JTextField length;
	JCheckBox caps;
	JCheckBox lower;
	JCheckBox digits;
	JCheckBox symbols;
	JButton ok;
	JButton hashText;
	JButton searchHash;
	JButton save;
	Clipboard clipBoard;
	
	File tableFile;
	File textFile;
	
	public GUI (){
		table = null;
		clipBoard = Toolkit.getDefaultToolkit().getSystemClipboard();
		JFileChooser browser = new JFileChooser();
		int choice = JOptionPane.showOptionDialog(null, "Do you want to use a:", "Start", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, new String[]{"New Table", "Old Table"}, null);
		if(choice == JOptionPane.CLOSED_OPTION){
			System.exit(0);
		}else if (choice ==1){
			browser.setFileFilter(new TableFileFilter());
			browser.setDialogTitle("Choose a Rainbow Table File");
			while(browser.showOpenDialog(this) == JFileChooser.CANCEL_OPTION) {
				if(JOptionPane.showConfirmDialog(this, "Do you want to quit?", "", JOptionPane.YES_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.YES_OPTION)
					System.exit(0);
			}
			tableFile = browser.getSelectedFile();
			browser.setFileFilter(new SetFileFilter());
			browser.setDialogTitle("Choose the Matching Plain Text Set File");
			while(browser.showOpenDialog(this) == JFileChooser.CANCEL_OPTION) {
				if(JOptionPane.showConfirmDialog(this, "Do you want to quit?", "", JOptionPane.YES_OPTION, JOptionPane.PLAIN_MESSAGE) == JOptionPane.YES_OPTION)
					System.exit(0);
			}
			textFile = browser.getSelectedFile();
			try {
				table = new RainbowTable(tableFile, textFile);
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (ClassNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		} else
			table = new RainbowTable();
		this.setVisible(true);
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setSize(500, 450);
		
		this.setTitle("RainbowTables");
		this.setLayout(null);
		//this.setResizable(false);
		
		ActionListener listener = new MyListener();
		
		textToHash = new JTextField("Text to hash");
		textToHash.setVisible(true);
		textToHash.setBounds(120, 10, 200, 20);
		textToHash.addActionListener(listener);
		 textToHash.addFocusListener(new FocusListener(){
			@Override
			public void focusGained(FocusEvent e) {
				textToHash.setText("");
			}
			@Override
			public void focusLost(FocusEvent e) {
			}
		});
		this.add(textToHash);
		
		searchForHash = new JTextField("Search for hash");
		searchForHash.setVisible(true);
		searchForHash.setBounds(120, 40, 200, 20);
		searchForHash.addActionListener(listener);
		searchForHash.addFocusListener(new FocusListener(){
			@Override
			public void focusGained(FocusEvent e) {
				searchForHash.setText("");
			}
			@Override
			public void focusLost(FocusEvent e) {
			}
		});
		this.add(searchForHash);
		
		hashToCrack = new JTextField("Hash to crack");
		hashToCrack.setVisible(true);
		hashToCrack.setBounds(120, 80, 280, 20);
		hashToCrack.addActionListener(listener);
		hashToCrack.addFocusListener(new FocusListener(){
			@Override
			public void focusGained(FocusEvent e) {
				hashToCrack.setText("");
			}
			@Override
			public void focusLost(FocusEvent e) {
			}
		});
		this.add(hashToCrack);
		
		length = new JTextField("Length of hash");
		length.setVisible(true);
		length.setBounds(120, 110, 100, 20);
      	length.addFocusListener(new FocusListener(){
			@Override
			public void focusGained(FocusEvent e) {
				length.setText("");
			}
			@Override
			public void focusLost(FocusEvent e) {
			}
		});
		this.add(length);
		
		caps = new JCheckBox("A-Z");
		caps.setVisible(true);
		caps.setBounds(120, 160, 50, 15);
		this.add(caps);
		
		lower = new JCheckBox("a-z");
		lower.setVisible(true);
		lower.setBounds(270,160,50,15);
		this.add(lower);
		
		digits = new JCheckBox("0-9");
		digits.setVisible(true);
		digits.setBounds(120, 210, 50, 15);
		this.add(digits);
		
		symbols = new JCheckBox("!- /");
		symbols.setVisible(true);
		symbols.setBounds(270, 210, 50, 15);
		this.add(symbols);
		
		ok = new JButton("OK");
		ok.setVisible(true);
		ok.setBounds(180, 240, 60, 25);
		ok.addActionListener(listener);
		this.add(ok);
		
		save = new JButton("Save Table");
		save.setVisible(true);
		save.setBounds(135, 290, 150, 30);
		save.addActionListener(listener);
		this.add(save);
		
		hashText = new JButton("Hash");
		hashText.setVisible(true);
		hashText.setBounds(320, 10, 80, 19);
		hashText.addActionListener(listener);
		this.add(hashText);
		
		searchHash = new JButton("Search");
		searchHash.setVisible(true);
		searchHash.setBounds(320, 40, 80, 19);
		searchHash.addActionListener(listener);
		this.add(searchHash);
		
		this.repaint();
	}
	
	class MyListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getSource().equals(ok) || e.getSource().equals(hashToCrack)){
				boolean[] checkBoxes = new boolean[4];
				checkBoxes[0]= caps.isSelected();
				checkBoxes[1] = lower.isSelected();
				checkBoxes[2] = digits.isSelected();
				checkBoxes[3]= symbols.isSelected();
				String plain = table.crackHash(hashToCrack.getText(), Integer.valueOf(length.getText()), checkBoxes);
				clipBoard.setContents(new StringSelection(plain), null);
				JOptionPane.showMessageDialog(null, plain, "", JOptionPane.PLAIN_MESSAGE);
			}else if (e.getSource().equals(searchHash) || e.getSource().equals(searchForHash)) {
				String plain = table.searchTable(searchForHash.getText());
				clipBoard.setContents(new StringSelection(plain), null);
				JOptionPane.showMessageDialog(null, plain, "", JOptionPane.PLAIN_MESSAGE);
			}else if (e.getSource().equals(hashText) || e.getSource().equals(textToHash)){
				StringBuilder hashOut = new StringBuilder();
				int[] hashBack = SHA1Hash.ShaHash(textToHash.getText());
				for(int i = 0; i < 5; i++)
					hashOut.append(Hex.encodeHexString(ByteBuffer.allocate(4).putInt(hashBack[i]).array()));
				//table.addToTable(hashOut.toString(), textToHash.getText());
				clipBoard.setContents(new StringSelection(hashOut.toString()), null);
				JOptionPane.showMessageDialog(null, hashOut.toString(), "", JOptionPane.PLAIN_MESSAGE);
			}else if (e.getSource().equals(save)){
				GUI.this.setVisible(false);
				JFileChooser browser = new JFileChooser();
				browser.setFileFilter(new TableFileFilter());
				browser.setDialogTitle("Where To Save Rainbow Table File");
				if(browser.showSaveDialog(GUI.this) == JFileChooser.CANCEL_OPTION) {
					return;
				}
				tableFile = (new TableFileFilter()).accept(browser.getSelectedFile())?browser.getSelectedFile():new File(browser.getSelectedFile()+".table");
				browser.setFileFilter(new SetFileFilter());
				browser.setDialogTitle("Where To Save Matching Plain Text Set File");
				if(browser.showSaveDialog(GUI.this) == JFileChooser.CANCEL_OPTION) {
					return;
				}
				textFile = (new SetFileFilter()).accept(browser.getSelectedFile())?browser.getSelectedFile():new File(browser.getSelectedFile()+".set");
				try {
					table.save(tableFile, textFile);
				} catch (FileNotFoundException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				GUI.this.setVisible(true);
			}
		}
	}
	
	private class TableFileFilter extends FileFilter{
		@Override
		public boolean accept(File f) {
			if (f.isDirectory())
			      return true;
			int last = f.getName().lastIndexOf('.');
			if(last == -1)
				return false;
			return f.getName().substring(last).equalsIgnoreCase(".table");
		}

		@Override
		public String getDescription() {
			return "Rainbow Table (.table)";
		}
	}
	
	private class SetFileFilter extends FileFilter{
		@Override
		public boolean accept(File f) {
			if (f.isDirectory())
			      return true;
			int last = f.getName().lastIndexOf('.');
			if(last == -1)
				return false;
			return f.getName().substring(last).equalsIgnoreCase(".set");
		}

		@Override
		public String getDescription() {
			return "Plain Text Set (.set)";
		}
	}
}
